package srv

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/asserts"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/beans"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/ferror"
	fgorms "gitee.com/lailonghui/vehicle-supervision-framework/pkg/gorms"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/loggers"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/pages"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/resultcode"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/scalars"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/sqls"
	"gitee.com/lailonghui/vehicle-supervision-framework/pkg/xids"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/dao"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/enums"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/gqlgen/mgr/gmodel"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/model"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/pkg/dbconn"
	"gitee.com/shiqiyue/xd-bi/internal/modules/cr/pkg/template"
	"gitee.com/shiqiyue/xd-bi/pkg/gorms"
	mapset "github.com/deckarep/golang-set"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/log"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"sync"
)

func Reportinit() {
	reportSrv := &ReportSrv{}
	err := beans.ProvideBean(reportSrv)
	asserts.Nil(err, err)
}

type ReportSrv struct {
	BaseSrv
	*dao.ReportDao        `inject:""`
	Db                    *gorm.DB               `inject:""`
	ReportFormDao         *dao.ReportFormDao     `inject:""`
	SqlReportSrv          *SqlReportSrv          `inject:""`
	ReportDbSrv           *ReportDbSrv           `inject:""`
	DictSrv               *DictSrv               `inject:""`
	DictCategorySrv       *DictCategorySrv       `inject:""`
	ReportResultColumnSrv *ReportResultColumnSrv `inject:""`
	ReportFormSrv         *ReportFormSrv         `inject:""`
	ReportAggregateSrv    *ReportAggregateSrv    `inject:""`
	ReportExecSrv         *ReportExecSrv         `inject:""`
}

func (s *ReportSrv) IsCodeValid(ctx context.Context, db *gorm.DB, code string, reportId *string) (bool, error) {
	db = db.Model(s.Model.GetModel()).Where("code = ?", code)
	if reportId != nil {
		db = db.Where("report_id != ?", &reportId)
	}
	var num int64
	err := db.Count(&num).Error
	if err != nil {
		return false, err
	}
	if num > 0 {
		return false, nil
	}
	return true, nil
}

// 更新状态
func (s *ReportSrv) ChangeStatus(ctx context.Context, db *gorm.DB, reportId string, status int) error {
	updateParam := map[string]interface{}{}
	updateParam["status"] = status
	return s.UpdateByUnionId(ctx, db, reportId, updateParam)
}

// 通过编号获取
func (s *ReportSrv) GetByCode(ctx context.Context, db *gorm.DB, code string, report *model.Report) error {
	err := db.Model(s.Model.GetModel()).Where("code = ?", code).First(report).Error
	return err
}

// 添加报表
func (s *ReportSrv) InsertReport(ctx context.Context, db *gorm.DB, req gmodel.InsertReportReq) error {
	var reportId = xids.GetXid(ctx)
	err := db.Transaction(func(tx *gorm.DB) error {
		report := &model.Report{
			ReportId:          reportId,
			Name:              req.Name,
			Type:              req.Type,
			Status:            enums.REPORT_STATUS_ACTIVE,
			Code:              req.Code,
			DisplayType:       req.DisplayType,
			DataAccessSupport: req.DataAccessSupport,
			PageSupport:       req.PageSupport,
			ShowSummary:       req.ShowSummary,
		}
		err := s.Insert(ctx, tx, report)
		if err != nil {
			return err
		}
		return nil
	})
	return err
}

// 执行报表
func (s *ReportSrv) ExecuteReport(ctx context.Context, db *gorm.DB, code string, params map[string]interface{}) (r ReportExecResult, err error) {
	var report model.Report
	fixParamType(params)
	err = s.GetByCode(ctx, db, code, &report)
	if err != nil {
		err = ferror.Wrap("通过编号获取报表异常", err)
		return
	}
	reportExec, err := s.ReportExecSrv.Start(ctx, report.ReportId, params)
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			s.ReportExecSrv.ExecFail(ctx, reportExec, err)
		} else {
			s.ReportExecSrv.ExecSuccess(ctx, reportExec)
		}
	}()
	if report.Type == enums.REPORT_TYPE_SQL {
		// 执行sql报表
		execResult, err1 := s.ExecSqlReport(ctx, db, params, report)
		if err1 != nil {
			err = ferror.Wrap("执行SQL报表异常", err1)
			return
		}
		return ReportExecResult{
			Count:     execResult.Count,
			Type:      enums.REPORT_TYPE_SQL,
			List:      execResult.List,
			Detail:    execResult.Detail,
			Sql:       []string{execResult.Sql},
			CountSql:  []string{execResult.CountSql},
			Aggregate: nil,
		}, nil
	} else if report.Type == enums.REPORT_TYPE_AGGREGATE {
		execResult, err1 := s.ExecAggregateReport(ctx, db, params, report)
		if err1 != nil {
			err = ferror.Wrap("执行聚合报表异常", err1)
			return
		}
		execResult.Type = enums.REPORT_TYPE_AGGREGATE
		return execResult, nil
	} else {
		err = ferror.New("不支持的报表查询")
		return
	}
}

// 执行聚合报表
func (s *ReportSrv) ExecAggregateReport(ctx context.Context, db *gorm.DB, params map[string]interface{}, report model.Report) (r ReportExecResult, err error) {
	// 如果是聚合报表，则获取所有连接的报表Form
	aggregates, err1 := s.ReportAggregateSrv.GetByReportId(ctx, db, report.ReportId)
	if err1 != nil {
		err = ferror.Wrap("获取聚合信息失败", err1)
		return
	}
	if len(aggregates) == 0 {
		return
	}
	missionMap := map[string]model.Report{}
	wg := sync.WaitGroup{}
	for _, aggregate := range aggregates {
		connectReport := model.Report{}
		err1 := s.GetByUnionId(ctx, db, aggregate.ConnectReportId, &connectReport)
		if err1 != nil {
			err = ferror.Wrap("获取关联的报表失败", err)
			return
		}
		missionMap[aggregate.AttributeName] = connectReport
	}
	wg.Add(len(missionMap))
	aggregateMap := sync.Map{}
	for k, v := range missionMap {
		go func(attributeName string, report model.Report) {
			defer wg.Done()
			sqlReport, err2 := s.ExecSqlReport(ctx, db, params, report)
			aggregateMap.Store(attributeName, &AggregateExecuteResult{
				ExecResult:    sqlReport,
				AttributeName: attributeName,
				Error:         err2,
			})
		}(k, v)
	}
	wg.Wait()
	r.Aggregate = make(map[string]interface{}, 0)
	aggregateMap.Range(func(key, value interface{}) bool {
		res := value.(*AggregateExecuteResult)
		if res.Error != nil {
			err = ferror.Wrap("执行报表异常", res.Error)
		}
		if res.ExecResult.DisplayType == enums.REPORT_DISPLAY_TYPE_LIST {
			r.Aggregate[res.AttributeName] = res.ExecResult.List
			r.Sql = append(r.Sql, res.ExecResult.Sql)
		} else if res.ExecResult.DisplayType == enums.REPORT_DISPLAY_TYPE_DETAIL {
			r.Aggregate[res.AttributeName] = res.ExecResult.Detail
			r.Sql = append(r.Sql, res.ExecResult.Sql)
		}

		return true
	})
	return
}

// 执行sql报表
func (s *ReportSrv) ExecSqlReport(ctx context.Context, db *gorm.DB, params map[string]interface{}, report model.Report) (r SqlReportExecResult, err error) {
	sqlReport, err1 := s.SqlReportSrv.GetByReportId(ctx, db, report.ReportId)
	if err1 != nil {
		err = ferror.Wrap("通过报表ID获取SQL报表异常", err1)
		return
	}
	var reportDb model.ReportDb
	err1 = s.ReportDbSrv.GetByUnionId(ctx, db, sqlReport.DbId, &reportDb)
	if err1 != nil {
		err = ferror.Wrap("通过DBID获取报表DB异常", err1)
		return
	}
	// 获取数据库链接
	conn, err1 := dbconn.GetConn(ctx, reportDb)
	if err1 != nil {
		err = ferror.Wrap("获取数据库链接异常", err1)
		return
	}
	queryParam := params
	// 数据权限处理
	span := opentracing.SpanFromContext(ctx)
	span.LogFields(log.Bool("DataAccessSupport", report.DataAccessSupport))
	if report.DataAccessSupport {
		err1 = sqls.FillAuthMap(ctx, queryParam)

		if err1 != nil {
			err = ferror.Wrap("数据权限处理异常", err1)
			return
		}
	}
	// 填充用户信息
	err1 = sqls.FillUserMap(ctx, queryParam)
	if err1 != nil {
		err = ferror.Wrap("填充用户信息异常", err1)
		return
	}

	// 分页参数处理
	if report.PageSupport {
		currentPage, ok := queryParam["currentPage"]
		if !ok {
			queryParam["currentPage"] = 1
			currentPage = 1
		}
		pageSize, ok := queryParam["pageSize"]
		if !ok {
			queryParam["pageSize"] = 10
			pageSize = 10
		}
		switch v := currentPage.(type) {
		case int:
			currentPage = v
		case float64:
			currentPage = int(v)
		case int64:
			currentPage = int(v)
		case json.Number:
			currentPage, _ = strconv.Atoi(v.String())
		}
		switch v := pageSize.(type) {
		case int:
			pageSize = v
		case float64:
			pageSize = int(v)
		case int64:
			pageSize = int(v)
		case json.Number:
			pageSize, _ = strconv.Atoi(v.String())
		}
		icurrentPage := currentPage.(int)
		ipageSize := pageSize.(int)
		limit, offset := pages.ToDbQuery(icurrentPage, ipageSize)
		queryParam["limit"] = limit
		queryParam["offset"] = offset
	}

	sql := sqlReport.Sql
	// 执行go template
	if sqlReport.SupportGoTemplate {
		sqlNew, err1 := template.ExecuteSqlTemplate(ctx, sqlReport, queryParam)
		if err1 != nil {
			err = ferror.Wrap("GO模板执行异常", err1)
			return
		}
		sql = sqlNew

	}
	span.LogFields(log.String("RawSql", sql), log.Object("QueryParams", queryParam))

	// 执行
	r.DisplayType = report.DisplayType
	if report.DisplayType == enums.REPORT_DISPLAY_TYPE_LIST {
		// 列表查询
		resultMap := make([]map[string]interface{}, 0)
		err1, r.Sql = executeSql(ctx, conn, sql, queryParam, &resultMap)
		if err1 != nil {
			err = ferror.Wrap("列表查询异常", err1)
			return
		}
		err1 := s.handleReturnColumn(ctx, db, resultMap, report)
		if err1 != nil {
			err = ferror.Wrap("处理返回结果(字典)异常", err1)
			return
		}
		r.List = resultMap
		return
	} else if report.DisplayType == enums.REPORT_DISPLAY_TYPE_PAGE {
		// 分页
		resultMap := make([]map[string]interface{}, 0)
		count := 0
		countSql := sqlReport.CountSql
		if sqlReport.SupportGoTemplate {
			countSqlNew, err1 := template.ExecuteCountSqlTemplate(ctx, sqlReport, queryParam)
			if err1 != nil {
				err = ferror.Wrap("GO模板执行错误", err1)
				return
			}
			countSql = countSqlNew
		}
		// 列表查询
		err1, r.Sql = executeSql(ctx, conn, sql, queryParam, &resultMap)
		if err1 != nil {
			err = ferror.Wrap("列表查询异常", err1)
			return
		}
		// 数量查询
		err1, r.CountSql = executeSql(ctx, conn, countSql, queryParam, &count)
		if err1 != nil {
			err = ferror.Wrap("数量查询异常", err1)
			return
		}
		err1 := s.handleReturnColumn(ctx, db, resultMap, report)
		if err1 != nil {
			err = ferror.Wrap("处理返回值(字典)异常", err1)
			return
		}
		r.List = resultMap
		r.Count = &count
		return
	} else if report.DisplayType == enums.REPORT_DISPLAY_TYPE_DETAIL {
		// 详情查询
		resultMap := make([]map[string]interface{}, 0)
		err1, r.Sql = executeSql(ctx, conn, sql, queryParam, &resultMap)
		if err1 != nil {
			err = ferror.Wrap("详情查询异常", err1)
			return
		}
		err1 := s.handleReturnColumn(ctx, db, resultMap, report)
		if err1 != nil {
			err = ferror.Wrap("处理返回值(字典)异常", err1)
			return
		}
		if resultMap != nil && len(resultMap) > 0 {
			r.Detail = resultMap[0]
		}

		return
	}
	err = ferror.New("不支持的SQL查询")
	return
}

// 处理入参
func fixParamType(m map[string]interface{}) {
	if len(m) == 0 {
		return
	}
	for k, v := range m {
		switch n := v.(type) {
		case json.Number:
			if strings.Index(n.String(), ".") >= 0 {
				m[k], _ = n.Float64()
			} else {
				m[k], _ = n.Int64()
			}
		case map[string]interface{}:
			for k2, v2 := range n {
				m[k+"_"+k2] = v2
			}

		}
	}
}

// 返回结果处理
func (s *ReportSrv) handleReturnColumn(ctx context.Context, db *gorm.DB, resultMap []map[string]interface{}, report model.Report) error {
	if len(resultMap) == 0 {
		return nil
	}
	reportResultColumns, err := s.ReportResultColumnSrv.GetByReportId(ctx, db, report.ReportId)
	if err != nil {
		return err
	}
	// 获取字典信息
	columnDictMap := map[string]map[interface{}]string{}
	// 返回类型Map
	returnColumnMap := map[string]model.ReportResultColumn{}
	for _, column := range reportResultColumns {
		returnColumnMap[column.AttributeName] = column
		if column.DictCategoryId != nil && *column.DictCategoryId != "" {
			categoryDetail, err := s.DictCategorySrv.GetByCategoryId(ctx, *column.DictCategoryId)
			if err != nil {
				return ferror.Wrap("获取字典分类失败", err)
			}
			if categoryDetail == nil {
				return ferror.Wrap("字典分类不存在", err)
			}
			dictMap, err := s.DictSrv.DictMapByCategory(ctx, *categoryDetail)
			if err != nil {
				return err
			}
			columnDictMap[column.AttributeName] = dictMap
		}
	}
	// 翻译字典
	for i, _ := range resultMap {
		for attributeName, value := range resultMap[i] {
			s.returnColumnTypeConvert(returnColumnMap, attributeName, value, resultMap, i)
			value = resultMap[i][attributeName]
			translateDictDone := s.translateDict(columnDictMap, attributeName, value, resultMap, i)
			if translateDictDone {
				continue
			}

		}
	}
	return nil

}

// 类型转换
func (s *ReportSrv) returnColumnTypeConvert(returnColumnMap map[string]model.ReportResultColumn, attribtueName string, value interface{}, resultMap []map[string]interface{}, i int) bool {
	resultColumn, ok := returnColumnMap[attribtueName]
	if !ok {
		return false
	}

	if resultColumn.Type == enums.BiResultType.Texts() {
		switch v := value.(type) {
		case string:
			if v != "" {
				resultMap[i][attribtueName] = fgorms.StrToTextArray(v)
			} else {
				resultMap[i][attribtueName] = []string{}
			}
		}
	}
	if resultColumn.Type == enums.BiResultType.Numbers() {
		switch v := value.(type) {
		case string:
			if v != "" {
				resultMap[i][attribtueName] = fgorms.StrToIntArray(v)
			} else {
				resultMap[i][attribtueName] = []int{}
			}
		}
	}

	return true
}

// 翻译字典
func (s *ReportSrv) translateDict(columnDictMap map[string]map[interface{}]string, attribtueName string, value interface{}, resultMap []map[string]interface{}, i int) bool {
	dictMap, ok := columnDictMap[attribtueName]
	if !ok {
		return false
	}
	if value == nil {
		return false
	}
	switch v := value.(type) {
	case int:
		resultMap[i][attribtueName] = dictMap[v]
		return true
	case int32:
		ni := int(v)
		resultMap[i][attribtueName] = dictMap[ni]
		return true
	case int64:
		ni := int(v)
		resultMap[i][attribtueName] = dictMap[ni]
		return true
	case string:
		resultMap[i][attribtueName] = dictMap[v]
		return true
	case []string:
		rs := make([]string, 0)
		for _, s2 := range v {
			if s2 == "" {
				continue
			}
			rs = append(rs, dictMap[s2])
		}
		resultMap[i][attribtueName] = rs
		return true
	case []int:
		rs := make([]string, 0)
		for _, s2 := range v {
			rs = append(rs, dictMap[s2])
		}
		resultMap[i][attribtueName] = rs
		return true
	default:
		panic("unsupport dict column value")
	}

}

// 获取报表的form参数
func (s *ReportSrv) GetFormByReportId(ctx context.Context, db *gorm.DB, reportId string) ([]model.ReportForm, error) {
	report := model.Report{}
	err := s.GetByUnionId(ctx, db, reportId, &report)
	if err != nil {
		return nil, ferror.Wrap("获取报表失败", err)
	}
	if report.Type == enums.REPORT_TYPE_AGGREGATE {
		// 如果是聚合报表，则获取所有连接的报表Form
		aggregates, err := s.ReportAggregateSrv.GetByReportId(ctx, db, reportId)
		if err != nil {
			return nil, ferror.Wrap("获取聚合信息失败", err)
		}
		reportIdSet := mapset.NewSet()
		for _, aggregate := range aggregates {
			reportIdSet.Add(aggregate.ReportId)
		}
		return s.ReportFormSrv.getByReportIds(ctx, db, reportIdSet.ToSlice())
	} else {
		return s.ReportFormSrv.GetByReportId(ctx, db, reportId)
	}
}

// 获取报表的form参数
func (s *ReportSrv) GetParamByReportId(ctx context.Context, db *gorm.DB, report model.Report) ([]*gmodel.ReportParam, error) {
	var params []*gmodel.ReportParam
	if report.Type == enums.REPORT_TYPE_AGGREGATE {
		// 如果是聚合报表，则获取所有连接的报表Form
		aggregates, err := s.ReportAggregateSrv.GetByReportId(ctx, db, report.ReportId)
		if err != nil {
			return nil, ferror.Wrap("获取聚合信息失败", err)
		}
		reportIdSet := mapset.NewSet()
		for _, aggregate := range aggregates {
			reportIdSet.Add(aggregate.ConnectReportId)
		}
		forms, err := s.ReportFormSrv.getByReportIds(ctx, db, reportIdSet.ToSlice())
		formSet := mapset.NewSet()
		if forms != nil {
			for i := range forms {
				if formSet.Contains(forms[i].AttributeName) {
					continue
				} else {
					formSet.Add(forms[i].AttributeName)
				}
				params = append(params, &gmodel.ReportParam{
					AttributeName: forms[i].AttributeName,
					Name:          forms[i].Name,
					Type:          forms[i].Type,
				})
			}
		}
		return params, nil
	}
	// SQL报表
	forms, err := s.ReportFormSrv.GetByReportId(ctx, db, report.ReportId)
	if err != nil {
		return nil, err
	}
	if forms != nil {
		for i := range forms {
			params = append(params, &gmodel.ReportParam{
				AttributeName: forms[i].AttributeName,
				Name:          forms[i].Name,
				Type:          forms[i].Type,
			})
		}
	}
	if report.PageSupport {
		params = append(params, &gmodel.ReportParam{
			AttributeName: "currentPage",
			Name:          "第几页",
			Type:          enums.REPORT_PARAM_TYPE_NUMBER,
		})
		params = append(params, &gmodel.ReportParam{
			AttributeName: "pageSize",
			Name:          "每页几条数据",
			Type:          enums.REPORT_PARAM_TYPE_NUMBER,
		})

	}

	return params, nil
}

// 获取报表API文档
func (s *ReportSrv) GetReportAPI(ctx context.Context, db *gorm.DB, report model.Report) ([]*gmodel.ReportAPIItem, error) {
	if report.Type == enums.REPORT_TYPE_SQL {
		return s.GetSqlReportAPI(ctx, db, report)
	} else if report.Type == enums.REPORT_TYPE_AGGREGATE {
		return s.GetAggregateReportAPI(ctx, db, report)
	} else {
		panic("error")
	}
}

func (s *ReportSrv) GetSqlReportAPI(ctx context.Context, db *gorm.DB, report model.Report) ([]*gmodel.ReportAPIItem, error) {
	columns, err := s.ReportResultColumnSrv.GetByReportId(ctx, db, report.ReportId)
	if err != nil {
		return nil, ferror.WrapWithCode("获取报表返回信息异常", resultcode.FAIL, err)
	}
	resultItems := []*gmodel.ReportAPIItem{}
	if report.DisplayType == enums.REPORT_DISPLAY_TYPE_LIST {
		listItem := &gmodel.ReportAPIItem{
			AttributeName: scalars.GetStringRef("List"),
			Name:          scalars.GetStringRef("列表"),
			Type:          scalars.GetStringRef("Object[]"),
			ID:            scalars.GetStringRef(xids.GetXid(ctx)),
			Children:      []*gmodel.ReportAPIItem{},
		}
		resultItems = append(resultItems, listItem)
		for i, column := range columns {
			listItem.Children = append(listItem.Children, &gmodel.ReportAPIItem{
				AttributeName: &columns[i].AttributeName,
				Name:          &columns[i].Name,
				Type:          scalars.GetStringRef(enums.BiResultType.ToText(column.Type)),
				ID:            scalars.GetStringRef(xids.GetXid(ctx)),
				Children:      nil,
			})
		}
	} else if report.DisplayType == enums.REPORT_DISPLAY_TYPE_DETAIL {
		listItem := &gmodel.ReportAPIItem{
			AttributeName: scalars.GetStringRef("Detail"),
			Name:          scalars.GetStringRef("详情"),
			Type:          scalars.GetStringRef("Object"),
			ID:            scalars.GetStringRef(xids.GetXid(ctx)),
			Children:      []*gmodel.ReportAPIItem{},
		}
		resultItems = append(resultItems, listItem)
		for i, column := range columns {
			listItem.Children = append(listItem.Children, &gmodel.ReportAPIItem{
				AttributeName: &columns[i].AttributeName,
				Name:          &columns[i].Name,
				Type:          scalars.GetStringRef(enums.BiResultType.ToText(column.Type)),
				ID:            scalars.GetStringRef(xids.GetXid(ctx)),
				Children:      nil,
			})
		}
	} else if report.DisplayType == enums.REPORT_DISPLAY_TYPE_PAGE {
		listItem := &gmodel.ReportAPIItem{
			AttributeName: scalars.GetStringRef("List"),
			Name:          scalars.GetStringRef("列表"),
			Type:          scalars.GetStringRef("Object[]"),
			ID:            scalars.GetStringRef(xids.GetXid(ctx)),
			Children:      []*gmodel.ReportAPIItem{},
		}
		countItem := &gmodel.ReportAPIItem{
			AttributeName: scalars.GetStringRef("Count"),
			Name:          scalars.GetStringRef("数量"),
			Type:          scalars.GetStringRef("Int"),
			ID:            scalars.GetStringRef(xids.GetXid(ctx)),
			Children:      []*gmodel.ReportAPIItem{},
		}
		resultItems = append(resultItems, listItem)
		resultItems = append(resultItems, countItem)
		for i, column := range columns {
			listItem.Children = append(listItem.Children, &gmodel.ReportAPIItem{
				AttributeName: &columns[i].AttributeName,
				Name:          &columns[i].Name,
				Type:          scalars.GetStringRef(enums.BiResultType.ToText(column.Type)),
				ID:            scalars.GetStringRef(xids.GetXid(ctx)),
				Children:      nil,
			})
		}
	}
	return resultItems, nil
}

func (s *ReportSrv) GetAggregateReportAPI(ctx context.Context, db *gorm.DB, report model.Report) ([]*gmodel.ReportAPIItem, error) {
	aggregates, err := s.ReportAggregateSrv.GetByReportId(ctx, db, report.ReportId)
	if err != nil {
		return nil, ferror.Wrap("获取聚合信息异常", err)
	}
	aggregateItem := &gmodel.ReportAPIItem{
		AttributeName: scalars.GetStringRef("Aggregate"),
		Name:          scalars.GetStringRef("聚合"),
		Type:          scalars.GetStringRef("Object"),
		Children:      []*gmodel.ReportAPIItem{},
		ID:            scalars.GetStringRef(xids.GetXid(ctx)),
	}
	for _, aggregate := range aggregates {
		connectReport := model.Report{}
		err := s.GetByUnionId(ctx, db, aggregate.ConnectReportId, &connectReport)
		if err != nil {
			return nil, ferror.Wrap("获取聚合报表异常", err)
		}
		t := &gmodel.ReportAPIItem{
			AttributeName: &aggregate.AttributeName,
			Name:          &connectReport.Name,
			Children:      []*gmodel.ReportAPIItem{},
			ID:            scalars.GetStringRef(xids.GetXid(ctx)),
		}
		aggregateItem.Children = append(aggregateItem.Children, t)
		if connectReport.DisplayType == enums.REPORT_DISPLAY_TYPE_DETAIL {
			t.Type = scalars.GetStringRef("Object")
		} else {
			t.Type = scalars.GetStringRef("Object[]")
		}
		columns, err := s.ReportResultColumnSrv.GetByReportId(ctx, db, aggregate.ConnectReportId)
		if err != nil {
			return nil, ferror.Wrap("获取报表返回信息异常", err)
		}
		for i, column := range columns {
			t.Children = append(t.Children, &gmodel.ReportAPIItem{
				AttributeName: &columns[i].AttributeName,
				Name:          &columns[i].Name,
				Type:          scalars.GetStringRef(enums.BiResultType.ToText(column.Type)),
				ID:            scalars.GetStringRef(xids.GetXid(ctx)),
				Children:      nil,
			})
		}
	}
	return []*gmodel.ReportAPIItem{aggregateItem}, nil
}

func (s *ReportSrv) ApiToMd(ctx context.Context, api *gmodel.ReportAPIResult) (string, error) {
	mdBs := bytes.Buffer{}

	mdBs.WriteString(fmt.Sprintf("# %s \n", api.Report.Name))
	mdBs.WriteString("- 请求URL \n")
	mdBs.WriteString(fmt.Sprintf("`bi/public/%s` \n", api.Report.Code))
	mdBs.WriteString("- 请求方式 \n")
	mdBs.WriteString("`HTTP请求(POST)` \n")
	mdBs.WriteString("- 请求头参数 \n")
	mdBs.WriteString("| 参数名 | 类型 | 说明 |  \n")
	mdBs.WriteString("| ------------- | ------ | ------------------------------- |  \n")
	mdBs.WriteString("| Authorization | String | 用户登录成功返回的令牌 |  \n")
	mdBs.WriteString("- 参数 \n")
	mdBs.WriteString("| 参数名 | 类型 | 说明 |  \n")
	mdBs.WriteString("| ------------- | ------ | ------------------------------- |  \n")
	for _, param := range api.RequestReportParams {
		mdBs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", param.AttributeName, enums.BiReportParamType.ToText(param.Type), param.Name))
	}
	mdBs.WriteString("- 返回参数 \n")
	mdBs.WriteString("| 参数名 | 类型 | 说明 | \n")
	mdBs.WriteString("| ------------- | ------ | ------------------------------- |  \n")
	apiItems := []*gmodel.ReportAPIItem{}
	err := json.Unmarshal([]byte(api.ResultStr), &apiItems)
	if err != nil {
		return "", err
	}
	for _, item := range apiItems {
		itemMd, err := s.apiResultItemToMd(ctx, 0, item)
		if err != nil {
			return "", err
		}
		mdBs.WriteString(itemMd)
	}
	return mdBs.String(), nil
}

func (s *ReportSrv) apiResultItemToMd(ctx context.Context, level int, item *gmodel.ReportAPIItem) (string, error) {
	bs := bytes.Buffer{}
	tabStr := ""
	for i := 0; i < level; i++ {
		tabStr = tabStr + "&nbsp;&nbsp;&nbsp;&nbsp;"
	}
	bs.WriteString(fmt.Sprintf("| %s | %s | %s | \n", tabStr+*item.AttributeName, *item.Type, *item.Name))
	if item.Children != nil && len(item.Children) > 0 {
		for _, child := range item.Children {
			childMd, err := s.apiResultItemToMd(ctx, level+1, child)
			if err != nil {
				return "", err
			}
			bs.WriteString(childMd)
		}
	}
	return bs.String(), nil
}

// 获取值
// 返回 值，是否数组
func getDictColumnValue(value interface{}) (interface{}, bool) {
	if value == nil {
		return nil, false
	}
	switch i := value.(type) {
	case int:
		return i, false
	case int32:
		ni := int(i)
		return ni, false
	case int64:
		ni := int(i)
		return ni, false
	case string:
		return i, false
	case []string:
		return i, true
	default:
		panic("unsupport dict column value")
	}
}

// 执行sql
func executeSql(ctx context.Context, conn *gorm.DB, sql string, queryParam map[string]interface{}, target interface{}) (err error, rawsql string) {
	sql = gorms.CleanSql(sql)
	if len(queryParam) > 0 {
		loggers.Debug("执行报表SQL:"+sql, ctx, zap.Any("参数", queryParam), zap.String("SQL", sql))
		d := conn.Raw(sql, queryParam)
		rawsql = gorms.GetSql(d)
		d = conn.Raw(rawsql)
		d.Scan(target)
		err = d.Error
		if err != nil {
			err = ferror.Wrap("执行SQL异常,错误的SQL为"+rawsql, err)
		}
		return
	}
	d := conn.Raw(sql)
	rawsql = gorms.GetSql(d)
	d = conn.Raw(rawsql)
	d.Scan(target)
	err = d.Error
	if err != nil {
		err = ferror.Wrap("执行SQL异常,错误的SQL为"+rawsql, err)

	}
	return

}
